#include "registeritemmodel.h"
#include "cpu.h"
#include "utilities.h"


RegisterItemModel::RegisterItemModel(QObject *parent) :
        QAbstractTableModel(parent), cpu(CPU::getInstance())
{
    connect(cpu, SIGNAL(registersChanged(int)), this, SLOT(updateRegister(int)));
}

RegisterItemModel::~RegisterItemModel()
{
}

int RegisterItemModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return CPU::T_REGISTERS;
}



int RegisterItemModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return NUM_OF_COLUMN;
}

QVariant RegisterItemModel::getRegistersValue(int index) const
{
    if(index >= 0 && index < CPU::G_REGISTERS)
    {
        return cpu->getRegister(index);
    }
    else
    {
        switch(index)
        {
        case CPU::ID_PC:
            {
                return cpu->getPC();
            }
        case CPU::ID_IR:
            {
                return cpu->getIR();
            }
        }
    }
    return QVariant();
}

void RegisterItemModel::updateRegister(int id)
{
    emit dataChanged(index(id, 0), index(id, NUM_OF_COLUMN - 1));
}

QString RegisterItemModel::getRegistersName(int index) const
{
    if(index >= 0 && index < CPU::G_REGISTERS)
    {
        return QString("R") + QString().setNum(index, 10);
    }
    else
    {
        switch(index)
        {
        case CPU::ID_PC:
            {
                return QString("PC");
            }
        case CPU::ID_IR:
            {
                return QString("IR");
            }
        default:
            {
                return QString();
            }
        }
    }
}

QVariant RegisterItemModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
    {
        return QVariant();
    }
    else if (index.row() >= rowCount(index) || index.column() >= columnCount(index))
    {
        return QVariant();
    }
    if(role == Qt::DisplayRole)
    {
        switch(index.column())
        {
        case REGISTER_NAME:
            {
                return getRegistersName(index.row());
            }
        case REGISTER_VALUE_BIN:
            {
                return getRegistersValue(index.row());
            }
        case REGISTER_VALUE_HEX:
            {
                QString result;
                if(index.row() == CPU::ID_PC)
                {
                    result = Utilities::uintToHex(getRegistersValue(index.row()).toLongLong());
                }
                else
                {
                    result = Utilities::binToHex(getRegistersValue(index.row()).toString());
                }
                return result;
            }
        case REGISTER_VALUE_DEC:
            {
                if(index.row() == CPU::ID_PC)
                {
                    return getRegistersValue(index.row()).toLongLong();
                }
                else
                {
                    return Utilities::binToDec(getRegistersValue(index.row()).toString());
                }
            }
        default:
            {
                return QVariant();
            }
        }
    }
    else
    {
        return QVariant();
    }
}

Qt::ItemFlags RegisterItemModel::flags(const QModelIndex &index) const
{
    if(index.isValid() && (index.column() == REGISTER_VALUE_HEX))
    {
        return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
    }
    else
    {
        return QAbstractTableModel::flags(index);
    }
}

bool RegisterItemModel::setData(const QModelIndex &_index, const QVariant &value, int role)
{
    if (_index.isValid() && role == Qt::EditRole)
    {
        QString input = value.toString();
        if(input.startsWith("X") || input.startsWith("x"))
        {
            input = input.mid(1);
        }
        if(_index.row() == CPU::ID_PC)
        {
            bool ok;
            quint32 value = input.toLongLong(&ok, 16);
            if(!ok)
            {
                return false;
            }
            cpu->setPC(value);
        }
        else
        {
            QString result = Utilities::hexToBin(input);
            if(result.size() != 32)
            {
                return false;
            }
            if(_index.row() == CPU::ID_IR)
            {
                cpu->setIR(result);
            }
            else
            {
                cpu->setRegisters(_index.row(), result);
            }
        }
        return true;
    }
    else
    {
        return false;
    }
}
